package Backend;

import java.io.File;
import java.io.IOException;
import org.snmp4j.TransportMapping;
import org.snmp4j.agent.BaseAgent;
import org.snmp4j.agent.CommandProcessor;
import org.snmp4j.agent.DuplicateRegistrationException;
import org.snmp4j.agent.MOGroup;
import org.snmp4j.agent.ManagedObject;
import org.snmp4j.agent.mo.MOTableRow;
import org.snmp4j.agent.mo.snmp.RowStatus;
import org.snmp4j.agent.mo.snmp.SnmpCommunityMIB;
import org.snmp4j.agent.mo.snmp.SnmpNotificationMIB;
import org.snmp4j.agent.mo.snmp.SnmpTargetMIB;
import org.snmp4j.agent.mo.snmp.StorageType;
import org.snmp4j.agent.mo.snmp.VacmMIB;
import org.snmp4j.agent.security.MutableVACM;
import org.snmp4j.mp.MPv3;
import org.snmp4j.security.SecurityLevel;
import org.snmp4j.security.SecurityModel;
import org.snmp4j.security.USM;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.Variable;
import org.snmp4j.transport.TransportMappings;

public class SnmpAgent extends BaseAgent {

    protected final String address;
    public static final String COMMUNITY = "public";
    public static final String COMMUNITY_SEC = "cpublic";

    public SnmpAgent(int identifier, String address) throws IOException {
        // bootCounter.agent - file for seralised boot-counter information
        // config.agent - file for seralised configuration information
        // CommandProcessor - class to handle SNMP requests
        super(new File("conf" + identifier + ".agent"), new File("bootCounter" + identifier + ".agent"), new CommandProcessor(new OctetString(MPv3.createLocalEngineID())));
        this.address = address;
    }

    public void start()throws IOException {
        init();
        addShutdownHook();
        getServer().addContext(new OctetString(COMMUNITY));
        finishInit();
        run();
        sendColdStartNotification();
    }

    @Override
    protected void registerManagedObjects() {
    }

    @Override
    protected void unregisterManagedObjects() {
    }

    @Override
    protected void addUsmUser(USM usm) {
    }

    @Override
    protected void addNotificationTargets(SnmpTargetMIB stmib, SnmpNotificationMIB snmib) {
    }

    @Override
    protected void addViews(VacmMIB mib) {
        mib.addGroup(SecurityModel.SECURITY_MODEL_SNMPv2c, new OctetString(
                COMMUNITY_SEC), new OctetString("v1v2group"),
                StorageType.nonVolatile);

        mib.addAccess(new OctetString("v1v2group"), new OctetString(COMMUNITY),
                SecurityModel.SECURITY_MODEL_ANY, SecurityLevel.NOAUTH_NOPRIV,
                MutableVACM.VACM_MATCH_EXACT, new OctetString("fullReadView"),
                new OctetString("fullWriteView"), new OctetString(
                "fullNotifyView"), StorageType.nonVolatile);

        // needs to add previous access values to tree family to give the client permission
        mib.addViewTreeFamily(new OctetString("fullReadView"), new OID("1.3"),
                new OctetString(), VacmMIB.vacmViewIncluded,
                StorageType.nonVolatile);
        mib.addViewTreeFamily(new OctetString("fullWriteView"), new OID("1.3"),
                new OctetString(), VacmMIB.vacmViewIncluded,
                StorageType.nonVolatile);
    }

    @Override
    protected void addCommunities(SnmpCommunityMIB mib) {
        Variable[] com2sec = new Variable[]{new OctetString(COMMUNITY),
            new OctetString(COMMUNITY_SEC), // security name
            getAgent().getContextEngineID(), // local engine ID
            new OctetString(COMMUNITY), // default context name
            new OctetString(), // transport tag
            new Integer32(StorageType.nonVolatile), // storage type
            new Integer32(RowStatus.active) // row status
        };

        MOTableRow row = mib.getSnmpCommunityEntry().createRow(
                new OctetString("public2public").toSubIndex(true), com2sec);
        mib.getSnmpCommunityEntry().addRow(row);
    }

    @Override
    protected void initTransportMappings() throws IOException {
        transportMappings = new TransportMapping[1];
        Address addr = GenericAddress.parse(address);
        TransportMapping tm = TransportMappings.getInstance()
                .createTransportMapping(addr);
        transportMappings[0] = tm;
    }
}
